import os
import subprocess
import shutil
import re
from typing import Iterable, Dict

from app.models.project import DirectoryNode, ProjectConfig


def _process_template(template_content: str, variables: Dict[str, str]) -> str:
    """处理模板文件，替换变量。"""
    result = template_content
    
    # 处理简单变量 {{VAR_NAME}}
    for key, value in variables.items():
        result = result.replace(f"{{{{{key}}}}}", str(value))
    
    # 处理条件块 {{#VAR}}...{{/VAR}}
    for key, value in variables.items():
        # 如果值存在，保留块内容
        if value:
            result = re.sub(
                rf"\{{\{{#{key}\}}\}}(.*?)\{{\{{/{key}\}}\}}",
                r"\1",
                result,
                flags=re.DOTALL
            )
        else:
            # 如果值不存在，删除整个块
            result = re.sub(
                rf"\{{\{{#{key}\}}\}}.*?\{{\{{/{key}\}}\}}",
                "",
                result,
                flags=re.DOTALL
            )
    
    return result


def _copy_code_templates(project_path: str, config: ProjectConfig):
    """复制代码模板文件到项目中。"""
    
    # 模板目录路径
    template_base = os.path.join(
        os.path.dirname(__file__),
        "../../../templates/code_templates"
    )
    
    framework_template_dir = os.path.join(template_base, config.uiFramework)
    
    if not os.path.exists(framework_template_dir):
        print(f"模板目录不存在: {framework_template_dir}")
        return
    
    # 准备模板变量
    template_vars = {
        "PROJECT_NAME": config.projectName,
        "UI_FRAMEWORK": config.uiFramework.capitalize(),
        "LANGUAGE": config.language or "typescript",
        "BUILD_TOOL": config.buildTool or "vite",
        "STATE_MANAGEMENT": config.stateManagement or "",
        "ROUTER": config.router or "",
        "DEV_PROXY": config.devProxy or "",
        "TEST_PROXY": config.testProxy or "",
        "PROD_PROXY": config.prodProxy or "",
    }
    
    # 遍历模板目录
    for root, dirs, files in os.walk(framework_template_dir):
        # 计算相对路径
        rel_path = os.path.relpath(root, framework_template_dir)
        target_dir = os.path.join(project_path, 'src', rel_path) if rel_path != '.' else os.path.join(project_path, 'src')
        
        # 特殊处理：config 目录放在项目根目录
        if 'config' in rel_path:
            target_dir = os.path.join(project_path, rel_path)

        # 特殊处理：env 模板文件直接放在项目根目录
        if rel_path.startswith('env'):
            target_dir = project_path
        
        os.makedirs(target_dir, exist_ok=True)
        
        for file in files:
            if not file.endswith('.template'):
                continue
            
            template_file = os.path.join(root, file)
            # 移除 .template 后缀
            target_file_name = file.replace('.template', '')
            target_file = os.path.join(target_dir, target_file_name)
            
            # 读取模板文件
            with open(template_file, 'r', encoding='utf-8') as f:
                template_content = f.read()
            
            # 处理模板变量
            processed_content = _process_template(template_content, template_vars)
            
            # 写入目标文件
            with open(target_file, 'w', encoding='utf-8') as f:
                f.write(processed_content)
            
            print(f"生成代码文件: {target_file}")


def _create_basic_project_structure(project_path: str, config: ProjectConfig):
    """创建基础项目目录结构。"""
    
    # 创建基础目录
    directories = [
        'src',
        'public',
        'docs',
    ]
    
    for directory in directories:
        dir_path = os.path.join(project_path, directory)
        os.makedirs(dir_path, exist_ok=True)
    
    # 创建 src 下的子目录
    src_subdirs = []
    
    if config.uiFramework == 'react':
        src_subdirs = ['components', 'pages', 'utils', 'assets', 'styles']
        if config.stateManagement and config.stateManagement != 'none':
            src_subdirs.append('store')
        if config.router and config.router != 'none':
            src_subdirs.append('router')
    elif config.uiFramework == 'vue':
        src_subdirs = ['components', 'views', 'utils', 'assets', 'styles']
        if config.stateManagement and config.stateManagement != 'none':
            src_subdirs.append('store')
        if config.router and config.router != 'none':
            src_subdirs.append('router')
    
    for subdir in src_subdirs:
        subdir_path = os.path.join(project_path, 'src', subdir)
        os.makedirs(subdir_path, exist_ok=True)
        # 创建 .gitkeep 文件保持目录
        gitkeep_path = os.path.join(subdir_path, '.gitkeep')
        with open(gitkeep_path, 'w', encoding='utf-8') as f:
            f.write('')


def _generate_setup_guide(project_path: str, config: ProjectConfig):
    """生成项目设置指南。"""
    
    guide_path = os.path.join(project_path, 'docs', 'SETUP_GUIDE.md')
    
    # 根据不同框架生成不同的命令
    framework_commands = {
        'react': {
            'vite': f"npm create vite@latest {config.projectName} -- --template react-ts",
            'webpack': f"npx create-react-app {config.projectName} --template typescript"
        },
        'vue': {
            'vite': f"npm create vite@latest {config.projectName} -- --template vue-ts",
            'webpack': f"npm create vue@latest {config.projectName}"
        }
    }
    
    build_tool = config.buildTool or 'vite'
    create_command = framework_commands.get(config.uiFramework, {}).get(build_tool, 
                     f"npm create vite@latest {config.projectName}")
    
    with open(guide_path, 'w', encoding='utf-8') as f:
        f.write(f"# {config.projectName} - 项目设置指南\n\n")
        
        # 环境准备
        f.write("## 环境准备\n\n")
        f.write("确保您的开发环境中已安装 Node.js (推荐LTS版本)。\n\n")
        f.write("### 检查 Node.js 版本\n\n")
        f.write("```bash\n")
        f.write("node --version\n")
        f.write("npm --version\n")
        f.write("```\n\n")
        f.write("推荐使用 Node.js 16.x 或更高版本。\n\n")
        
        # 项目创建命令
        f.write("## 创建项目\n\n")
        f.write(f"您选择的前端框架是 **{config.uiFramework.capitalize()}**，")
        f.write(f"构建工具是 **{build_tool.capitalize()}**。\n\n")
        f.write("创建项目的命令如下（请根据实际情况调整）：\n\n")
        f.write("```bash\n")
        f.write(f"{create_command}\n")
        f.write("cd " + config.projectName + "\n")
        f.write("npm install\n")
        f.write("```\n\n")
        
        # 安装依赖
        f.write("## 安装项目依赖\n\n")
        f.write("根据您的配置，需要安装以下依赖：\n\n")
        
        dependencies = []
        
        # 基础组件
        if config.baseComponents:
            dependencies.extend(config.baseComponents)
        
        # 扩展组件
        if config.extendedComponents:
            dependencies.extend(config.extendedComponents)
        
        # 状态管理
        if config.stateManagement:
            if config.stateManagement == 'redux-toolkit':
                dependencies.extend(['@reduxjs/toolkit', 'react-redux'])
            elif config.stateManagement == 'zustand':
                dependencies.append('zustand')
            elif config.stateManagement == 'pinia':
                dependencies.append('pinia')
            elif config.stateManagement == 'vuex':
                dependencies.append('vuex')
        
        # 路由
        if config.router:
            if config.router == 'react-router':
                dependencies.append('react-router-dom')
            elif config.router == 'vue-router':
                dependencies.append('vue-router')
        
        if dependencies:
            # 去重
            dependencies = list(set(dependencies))
            f.write("```bash\n")
            f.write("npm install " + " ".join(dependencies) + "\n")
            f.write("```\n\n")
        
        # 运行项目
        f.write("## 运行项目\n\n")
        f.write("安装完成后，可以使用以下命令启动开发服务器：\n\n")
        f.write("```bash\n")
        f.write("npm run dev\n")
        f.write("```\n\n")
        f.write("默认情况下，应用将在 `http://localhost:5173` (对于 Vite) 或 `http://localhost:3000` (对于 Create React App) 上运行。\n\n")
        
        # 构建项目
        f.write("## 构建项目\n\n")
        f.write("当准备部署到生产环境时，使用以下命令构建：\n\n")
        f.write("```bash\n")
        f.write("npm run build\n")
        f.write("```\n\n")
        
        # 项目配置信息
        f.write("## 项目配置信息\n\n")
        f.write(f"- **项目名称**: {config.projectName}\n")
        f.write(f"- **项目类型**: {config.projectType}\n")
        f.write(f"- **UI框架**: {config.uiFramework}\n")
        f.write(f"- **编程语言**: {config.language or 'typescript'}\n")
        f.write(f"- **构建工具**: {build_tool}\n")
        f.write(f"- **目标平台**: {config.targetPlatform or 'web'}\n")
        
        if config.stateManagement:
            f.write(f"- **状态管理**: {config.stateManagement}\n")
        if config.router:
            f.write(f"- **路由**: {config.router}\n")
        if config.layout:
            f.write(f"- **布局**: {config.layout}\n")
        
        f.write("\n")
        
        # 目录结构
        if config.directorySummary:
            f.write("## 目录结构说明\n\n")
            f.write(config.directorySummary + "\n\n")
        
        # 其他说明
        f.write("## 其他说明\n\n")
        if config.description:
            f.write(f"**项目描述**: {config.description}\n\n")
        
        if config.customRequirements:
            f.write(f"**自定义需求**: {config.customRequirements}\n\n")
        
        f.write("本项目由 AI前端项目生成系统自动生成。\n")
        f.write("更多信息请查看项目根目录下的 README.md 文件。\n")


def _generate_package_json(project_path: str, config: ProjectConfig):
    """生成 package.json 模板文件。"""
    import json
    
    package_json_path = os.path.join(project_path, 'package.json.template')
    
    # 构建依赖列表
    dependencies = {}
    dev_dependencies = {}
    
    # 基础框架依赖
    if config.uiFramework == 'react':
        dependencies['react'] = '^18.2.0'
        dependencies['react-dom'] = '^18.2.0'
        dev_dependencies['@types/react'] = '^18.2.0'
        dev_dependencies['@types/react-dom'] = '^18.2.0'
    elif config.uiFramework == 'vue':
        dependencies['vue'] = '^3.3.0'
    
    # TypeScript
    if config.language == 'typescript':
        dev_dependencies['typescript'] = '^5.0.0'
    
    # 构建工具
    if config.buildTool == 'vite':
        dev_dependencies['vite'] = '^4.4.0'
        if config.uiFramework == 'react':
            dev_dependencies['@vitejs/plugin-react'] = '^4.0.0'
        elif config.uiFramework == 'vue':
            dev_dependencies['@vitejs/plugin-vue'] = '^4.0.0'
    
    # 基础组件
    if config.baseComponents:
        for comp in config.baseComponents:
            dependencies[comp] = 'latest'
    
    # 扩展组件
    if config.extendedComponents:
        for comp in config.extendedComponents:
            dependencies[comp] = 'latest'
    
    # 状态管理
    if config.stateManagement:
        if config.stateManagement == 'redux-toolkit':
            dependencies['@reduxjs/toolkit'] = '^1.9.0'
            dependencies['react-redux'] = '^8.1.0'
        elif config.stateManagement == 'zustand':
            dependencies['zustand'] = '^4.4.0'
        elif config.stateManagement == 'pinia':
            dependencies['pinia'] = '^2.1.0'
        elif config.stateManagement == 'vuex':
            dependencies['vuex'] = '^4.1.0'
    
    # 路由
    if config.router:
        if config.router == 'react-router':
            dependencies['react-router-dom'] = '^6.15.0'
        elif config.router == 'vue-router':
            dependencies['vue-router'] = '^4.2.0'
    
    package_data = {
        "name": config.projectName,
        "version": "0.1.0",
        "private": True,
        "description": config.description or f"A {config.uiFramework} project",
        "scripts": {
            "dev": "vite" if config.buildTool == 'vite' else "react-scripts start",
            "build": "vite build" if config.buildTool == 'vite' else "react-scripts build",
            "preview": "vite preview" if config.buildTool == 'vite' else "serve -s build",
        },
        "dependencies": dependencies,
        "devDependencies": dev_dependencies
    }
    
    with open(package_json_path, 'w', encoding='utf-8') as f:
        json.dump(package_data, f, indent=2, ensure_ascii=False)


def _sanitize_name(name: str) -> str:
    """Normalize folder names to avoid OS conflicts."""

    sanitized = name.strip().replace(" ", "-").replace("/", "-").replace("\\", "-").lower()
    return sanitized or "unnamed"


def _create_directory_tree(base_path: str, nodes: Iterable[DirectoryNode]):
    """Create folders and placeholder files based on the configured tree."""

    for node in nodes:
        dir_name = _sanitize_name(node.name)
        dir_path = os.path.join(base_path, dir_name)
        os.makedirs(dir_path, exist_ok=True)

        for file_name in node.files:
            normalized = file_name.strip().replace("\\", "/").lstrip("/")
            file_path = os.path.join(dir_path, normalized)
            os.makedirs(os.path.dirname(file_path), exist_ok=True)
            if not os.path.exists(file_path):
                with open(file_path, "w", encoding="utf-8") as handler:
                    if node.description:
                        handler.write(f"// {node.description}\n")
                    handler.write(f"// TODO: 实现 {normalized}\n")

        if node.children:
            _create_directory_tree(dir_path, node.children)


def create_project_structure(config: ProjectConfig) -> str:
    """Generate the project structure based on the provided configuration."""

    print(f"接收到生成请求: {config.projectName}")
    print(f"项目类型: {config.projectType}, UI框架: {config.uiFramework}")

    output_dir = os.path.abspath(os.path.join(os.getcwd(), "..", "generated_projects"))
    os.makedirs(output_dir, exist_ok=True)

    project_path = os.path.join(output_dir, config.projectName)

    if os.path.exists(project_path):
        raise FileExistsError(f"项目目录 '{project_path}' 已存在。")

    if config.projectType == "react" and config.uiFramework == "antd":
        try:
            command = [
                "npm",
                "create",
                "vite@latest",
                config.projectName,
                "--",
                "--template",
                "react-ts",
            ]
            subprocess.run(command, check=True, cwd=output_dir, text=True, shell=True)
        except subprocess.CalledProcessError as err:
            raise RuntimeError(f"执行 Vite 创建命令失败: {err.stderr}") from err
        except Exception as err:  # pylint: disable=broad-except
            raise RuntimeError(f"发生未知错误: {err}") from err
    else:
        print(f"模拟为 {config.projectName} 创建目录...")
        os.makedirs(project_path)
        
        # 创建基础项目结构
        _create_basic_project_structure(project_path, config)
        
        # 复制代码模板文件
        _copy_code_templates(project_path, config)
        
        # 生成设置指南
        _generate_setup_guide(project_path, config)
        
        # 生成 package.json 模板
        _generate_package_json(project_path, config)

    has_directory_structure = bool(config.directoryStructure)

    if has_directory_structure:
        _create_directory_tree(project_path, config.directoryStructure)

    readme_path = os.path.join(project_path, "README.md")
    with open(readme_path, "w", encoding="utf-8") as handler:
        handler.write(f"# {config.projectName}\n\n")
        
        if config.description:
            handler.write(f"{config.description}\n\n")
        
        handler.write("## 快速开始\n\n")
        handler.write("请查看 [docs/SETUP_GUIDE.md](docs/SETUP_GUIDE.md) 获取详细的设置和安装指南。\n\n")
        
        handler.write("## 项目信息\n\n")
        handler.write(f"- **类型**: {config.projectType}\n")
        handler.write(f"- **框架**: {config.uiFramework}\n")
        if config.language:
            handler.write(f"- **语言**: {config.language}\n")
        if config.buildTool:
            handler.write(f"- **构建工具**: {config.buildTool}\n")
        if config.stateManagement:
            handler.write(f"- **状态管理**: {config.stateManagement}\n")
        if config.router:
            handler.write(f"- **路由**: {config.router}\n")
        
        if config.directorySummary:
            handler.write(f"\n## 目录结构概览\n\n{config.directorySummary}\n")
        
        if has_directory_structure:
            handler.write("\n## 目录结构\n\n")

            def write_tree(nodes: Iterable[DirectoryNode], indent: int = 0):
                prefix = "  " * indent
                for child in nodes:
                    handler.write(f"{prefix}- {child.name}")
                    if child.description:
                        handler.write(f" - {child.description}")
                    handler.write("\n")
                    if child.children:
                        write_tree(child.children, indent + 1)

            write_tree(config.directoryStructure)
        
        handler.write("\n## 开发指南\n\n")
        handler.write("本项目由 AI前端项目生成系统自动生成。\n\n")
        handler.write("更多信息和详细设置步骤，请参阅 `docs/SETUP_GUIDE.md`。\n")

    

    return project_path
